package groovyhelper;

import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
import com.intellij.psi.PsiFile;

import javax.swing.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.*;

public class GroovyCodeCompletionAction extends GroovyBaseOverrideAction {
    void groovyActionPerformed(AnActionEvent anActionEvent, final Editor editor, final Project project, PsiFile psiFile) {
        final int offset = editor.getCaretModel().getOffset();
        String text = editor.getDocument().getText();
        final int wordStart = findStartOfWord(text, offset);
        if (true || wordStart == 0 || text.charAt(wordStart-1) != '.') {
            String[] topLevelMethods = getTopLevelMethods(text, text.substring(wordStart, offset));
            if (topLevelMethods.length == 1) {
                substitute(editor, wordStart, offset, topLevelMethods[0], project, -1);
            } else if (topLevelMethods.length > 1) {
                final JList jlist = new JList(topLevelMethods);
                Runnable runnable = new Runnable() {
                    public void run() {
                        String method = (String) jlist.getSelectedValue();
                        substitute(editor, wordStart, offset, method, project, -1);
                    }
                };
                (new PopupChooserBuilder(jlist)).setItemChoosenCallback(runnable).createPopup().showInBestPositionFor(editor);
            }
        }
    }

    private int findStartOfWord(String text, int offset) {
        while (offset > 0 && isWordChar(text.charAt(offset - 1))) {
            offset--;
        }
        return offset;
    }

    private boolean isWordChar(char ch) {
        return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_';
    }

    private String[] getTopLevelMethods(String text, String startsWith) {
//        Map map = splitIntoClasses(text);
//        System.out.println("map = " + map);
        List<String> methods = new ArrayList<String>();
        Pattern pattern = Pattern.compile("def (\\w+)\\s*\\(");
        Matcher matcher = pattern.matcher(text);
        while(matcher.find()) {
            int index = matcher.start(1);
            String methodName = matcher.group(1);
            if (startsWith == null || methodName.startsWith(startsWith)) {
                methods.add(methodName+"()");
            }
        }
        return methods.toArray(new String[methods.size()]);
    }

    private Map splitIntoClasses(String text) {
        Map map = new HashMap();
        int lastEnd = 0;
        Pattern pattern = Pattern.compile("^.*class (\\w+)\\s*\\{", Pattern.MULTILINE);
        Matcher matcher = pattern.matcher(text);
        StringBuffer sb = new StringBuffer();
        while(matcher.find()) {
            String className = matcher.group(1);
            int classStart = matcher.end() -1;
            int classEnd = findMatchingBrace(text, classStart);
            map.put(className, text.substring(classStart, classEnd));
            sb.append(text.substring(lastEnd, matcher.start()));
            lastEnd = classEnd;
        }
        sb.append(text.substring(lastEnd));
        map.put("", sb.toString());
        return map;
    }

    private int findMatchingBrace(String text, int start) {
        char[] chars = text.toCharArray();
        int braces=0;
        for (int i = start; i < chars.length; i++) {
            char ch = chars[i];
            if (ch=='{') {
                braces++;
            } else if (ch=='}') {
                braces--;
                if (braces == 0) {
                    return i + 1;
                }
            }
        }
        return chars.length;
    }
}
